package at.fhooe.mcm.logic.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.HashMap;
import java.util.Map;

import at.fhooe.mcm.logic.core.Core;
import at.fhooe.mcm.logic.core.UpdateableService;
import at.fhooe.mcm.logic.logging.ConsoleLoggingService;

public class NetworkService implements UpdateableService
{

	public static final String				NAME			= "core.networkservice";
	public static final String				LOGGING_SOURCE	= "Network";

	private DatagramChannel					m_channel;
	private ByteBuffer						m_buffer		= ByteBuffer.allocate(1024);
	private Map<SocketAddress, PeerImpl>	m_peers			= new HashMap<SocketAddress, PeerImpl>();
	private Core							m_core;

	public static NetworkService getInstance(Core _core)
	{
		return (NetworkService) _core.getService(NAME);
	}

	public NetworkService() throws IOException
	{
		m_channel = DatagramChannel.open();
		m_channel.configureBlocking(false);

		int bufferSize = m_channel.socket().getReceiveBufferSize();
		m_buffer = ByteBuffer.allocate(bufferSize);
	}

	public NetworkService(int _port) throws IOException
	{
		this();
		m_channel.socket().bind(new InetSocketAddress(_port));
	}

	public Peer createPeer(String _hostname, int _port)
	{
		return createPeer(new InetSocketAddress(_hostname, _port));
	}

	public void destroyPeer(Peer _peer)
	{
		m_peers.remove(_peer);
	}

	private PeerImpl createPeer(SocketAddress _address)
	{
		PeerImpl peer = new PeerImpl(m_core, _address);
		m_peers.put(_address, peer);

		return peer;
	}

	private void receiveData() throws IOException
	{
		m_buffer.clear();
		SocketAddress address = m_channel.receive(m_buffer);

		while (address != null)
		{
			PeerImpl peer = m_peers.get(address);
			if (peer == null)
			{
				peer = createPeer(address);
			}

			m_buffer.flip();
			peer.putPackage(m_buffer);

			m_buffer.clear();
			address = m_channel.receive(m_buffer);
		}
	}

	@Override
	public void update()
	{
		try
		{
			receiveData();

			for (PeerImpl peer : m_peers.values())
			{
				peer.update(m_channel);
			}

		}
		catch (IOException e)
		{
			ConsoleLoggingService.getInstance(m_core).logDebug(LOGGING_SOURCE, e.getMessage());
		}
	}

	@Override
	public String getName()
	{
		return NAME;
	}

	@Override
	public void initialize(Core _core)
	{
		m_core = _core;
	}

	@Override
	public void shutdown(Core core)
	{
		// TODO Auto-generated method stub
		
	}
}
